#######################################################
# Example of coupled DEVS using DEVS timers 
# Author: moonho.hwang@gmail.com
#   Date: Oct.19.2011
#######################################################

from XSY.DEVS.Simulatable import *
from XSY.DEVS.CoupledDEVS import *
from XSY.DEVS.SimEngine import SimEngine

class Timer(DEVS):
   def __init__(self, n, duration, parent=None, tl=0, tn=float('inf') ):
      DEVS.__init__(self, n, parent, tl, tn)
      self.duration =duration
      self.phase = 'w'
      self.counter = 0
      self.addInputPorts("ip")

   def delta_0(self):
      '''reset the initial state'''
      self.counter = 0
      self.phase = 'w'
      self.sigma = self.duration 

   def ta(self):
      '''return sigma'''
      return self.sigma

   def delta_ext(self, x):
      '''external transition function'''
      self.counter = 0
      if self.phase == 'w': 
         self.phase = 'i'
         print "%s becomes idle."%self.parent_hier_name_to_s()
         self.sigma = float('inf')
      else:
         self.phase = 'w'
         print "%s becomes working."%self.parent_hier_name_to_s()
         self.sigma = self.duration 
      #i = raw_input("return") # activate this line for debuggin

   def _lambda(self):
      '''output function'''
      if self.phase == 'S':
         return PortValue(self.OP["!s"])

   def delta_int(self):
      '''internal transition function'''
      #print "\a" # so noisy so commented out
      print "\n############################################################### by %s"% self.parent_hier_name_to_s()
      self.counter += 1

   
   def state_to_s(self):
      '''display the current state into a string'''
      s = self.phase +", sigma=" + str(self.sigma) + ",c=" + str(self.counter)
      return s
#end of Timer

def make_input_event(two_timers, JSONarg=None):
   ''' a callback function for injection'''
   ipn = raw_input('ip1 or ip2>')
   if ipn in two_timers.IP:
      ip = two_timers.IP[ipn]
      return PortValue(ip)
   else:
      return None # inject None into timer 

def makeModel():
   md1 = Timer("timer1", 3.3)
   md2 = Timer("timer2", 6.6)
   cmd = CoupledDEVS("system")
   cmd.addComponents(md1); cmd.addComponents(md2)
   cmd.addInputPorts("ip1", "ip2")
   cmd.addCouple(cmd.IP["ip1"], md1.IP["ip"])
   cmd.addCouple(cmd.IP["ip2"], md2.IP["ip"])
   return cmd

if  __name__ == '__main__' :
   print 'This example shows a coupled model "system" having two timers "timer1" and "timer2" '
   print 'which can be activate/deactivate by injection of "ip1" or "ip2", resectively'
   print 'Initially, they are activated by frequency 3.3 and 6.6, respectively\n'

   cmd = makeModel()  
   engine = SimEngine(cmd, make_input_event)

   #---- setting StepByStep and DES simulation only ----
   engine.StepByStep = True
   engine.sfactor = float('inf')
   #----------------------------------------------------

   engine.runInteractiveMenu()

